package JVM;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class TestThreadLocal {

    private static final int THREAD_POOL_LENGTH = 10;
    private static final int THREAD_COUNT = 11;
    private static final int ATOMICINTEGER_INIT_VALUE = 0;
    private static final int SLEEP_LENGTH = 1000;

    public static void main(String[] args) throws InterruptedException {

        ExecutorService ex = Executors.newFixedThreadPool(THREAD_POOL_LENGTH);
        TestThread testThread = new TestThread() {
            @Override
            protected void finalize() throws Throwable {
                System.out.println("testThread回收");
            }
        };

        for(int i=0; i<THREAD_COUNT; ++i) {
            ex.execute(testThread);
        }

        TestThread.countDownLatch.await();
        System.out.println("任务1完成");

        TestThread.threadLocal = null;
        System.gc();
        System.out.println("第1次gc");

        Thread.sleep(SLEEP_LENGTH);

        TestThread.threadLocal = new ThreadLocal<TestKey>();
        TestThread.countDownLatch = new CountDownLatch(THREAD_COUNT);
        for(int i=0; i<THREAD_COUNT; ++i) {
            ex.execute(testThread);
        }

        TestThread.countDownLatch.await();
        System.out.println("任务2完成");

        System.gc();
        System.out.println("第2次gc");

        Thread.sleep(SLEEP_LENGTH);

        ex.shutdown();
    }

    private static class TestKey {
        Integer key;

        public TestKey(Integer integer) {
            key = integer;
        }

        @Override
        public String toString() {
            return String.valueOf(key);
        }

        @Override
        protected void finalize() throws Throwable {
            System.out.println("回收TestKey:"+key);
        }
    };

    private static class TestThread implements Runnable {

        private static AtomicInteger atomicInteger = new AtomicInteger(ATOMICINTEGER_INIT_VALUE);
        public static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);

        public static ThreadLocal<TestKey> threadLocal = new ThreadLocal<TestKey>() {
            @Override
            protected void finalize() throws Throwable {
                System.out.println("回收threadlocal:" + this);
            }
        };

        @Override
        public void run() {
            TestKey key = new TestKey(atomicInteger.incrementAndGet());

            threadLocal.set(key);
            System.out.println("线程："+Thread.currentThread()+":"+ key);
        //    threadLocal.remove();  // 这一句不加仍然导致内存泄漏
            try {
                Thread.sleep(SLEEP_LENGTH);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();

        }
    }
}
